#ifndef __MY_DATA__
#define __MY_DATA__
#include "util.hpp"
#include "config.hpp"
#include <unordered_map>
#include <pthread.h>
namespace cloud
{
    // 数据信息
    typedef struct BackupInfo_t
    {
        bool pack_flag;        // 是否压缩标志
        size_t fsize;          // 文件大小
        time_t atime;          // 最后一次访问时间
        time_t mtime;          // 最后一次修改时间
        std::string real_path; // 文件实际存储的路径名称
        std::string pack_path; // 压缩包存储的路径名称
        std::string url_path;  // 文件下载的路径名称
        bool NewBackupInfo(const std::string realpath)
        {
            FileUtil fu(realpath);
            if (fu.Exists() == false)
            {
                std::cout << "realpath not exist" << std::endl;
                return false;
            }
            pack_flag = 0;
            fsize = fu.FileSize();
            atime = fu.LassATime();
            mtime = fu.LassMTime();
            real_path = realpath;
            //./backdir/a.txt --> ./packdir/a.txt.lz
            Config *config = Config::GetInstance();
            std::string packdir = config->GetPackDir();
            std::string packdirsuffix = config->GetPackFileSuffix();
            std::string filename = fu.FileName();
            pack_path = packdir + filename + packdirsuffix;
            std::string downloadprefix = config->GetDownloadPrefix();
            url_path = downloadprefix + filename;
            return true;
        }
    } BackupInfo;
    class DataManager
    {
    private:
        std::string _backup_file;                           // 持久化存储文件
        std::unordered_map<std::string, BackupInfo> _table; // 内存中以hash表存储
        pthread_rwlock_t _rwlock;                           // 读写锁--读共享，写互斥
    public:
        DataManager()
        {
            _backup_file = Config::GetInstance()->GetBackupFile();
            pthread_rwlock_init(&_rwlock, nullptr);
            InitLoad(); //加载数据
        }
        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock);
        }
        bool Storage() // 每次数据新增或修改都要重新持久化存储，避免数据丢失
        {
            // 1.提取所有的数据
            std::vector<BackupInfo> arry;
            this->GetAll(&arry);
            // 2.将数据保存到Json::Value中
            Json::Value root;
            for (auto &a : arry)
            {
                Json::Value item;
                item["pack_flag"] = a.pack_flag;
                item["fsize"] = (Json::Int64)a.fsize;
                item["atime"] = (Json::Int64)a.atime;
                item["mtime"] = (Json::Int64)a.mtime;
                item["real_path"] = a.real_path;
                item["pack_path"] = a.pack_path;
                item["url_path"] = a.url_path;
                root.append(item);
            }
            // 3.序列化
            std::string body;
            JsonUtil::Serialize(root, &body);
            // 4.将数据写入文件
            FileUtil fu(_backup_file);
            fu.SetContent(body);
            return true;
        }
        bool InitLoad() // 初始化加载，在每次系统重启都要加载以前的数据
        {
            // 1.从文件中加载数据
            FileUtil fu(_backup_file);
            if (fu.Exists() == false)
                return false;
            std::string body;
            fu.GetContent(&body);
            // 2.对数据反序列化
            Json::Value root;
            JsonUtil::UnSerialize(body, &root);
            // 3.将数据添加表格中
            for (int i = 0; i < root.size(); i++)
            {
                BackupInfo info;
                info.pack_flag = root[i]["pack_flag"].asBool();
                info.fsize = root[i]["fsize"].asInt64();
                info.atime = root[i]["atime"].asInt64();
                info.mtime = root[i]["mtime"].asInt64();
                info.real_path = root[i]["real_path"].asString();
                info.pack_path = root[i]["pack_path"].asString();
                info.url_path = root[i]["url_path"].asString();
                _table[info.url_path] = info;
            }
            return true;
        }
        bool Insert(const BackupInfo &info) // 新增
        {
            pthread_rwlock_wrlock(&_rwlock);
            std::string url = info.url_path;
            _table[url] = info;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }
        bool Updata(const BackupInfo &info) // 修改->更新
        {
            pthread_rwlock_wrlock(&_rwlock);
            std::string url = info.url_path;
            _table[url] = info;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }
        bool GetOneByUrl(const std::string &url, BackupInfo *info) // 根据url获取数据信息
        {
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _table.find(url);
            if (it == _table.end())
            {
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            *info = it->second;
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
        bool GetOneByRealpath(const std::string &path, BackupInfo *info) // 根据实际路径获取数据信息
        {
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _table.begin();
            for (; it != _table.end(); it++)
            {
                if (it->second.real_path.compare(path) == 0)
                {
                    *info = it->second;
                    pthread_rwlock_unlock(&_rwlock);
                    return true;
                }
            }
            pthread_rwlock_unlock(&_rwlock);
            return false;
        }
        bool GetAll(std::vector<BackupInfo> *arry) // 获取所有的数据信息
        {
            pthread_rwlock_wrlock(&_rwlock);
            for (auto it = _table.begin(); it != _table.end(); it++)
            {
                arry->push_back(it->second);
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
    };
}

#endif